#include "Triangle.h"
#include "Ray.h"

//The initialized Triangle ructor
Triangle::Triangle(Vector3 p0,  Vector3 n0,  Vector3 p1,  Vector3 n1,  Vector3 p2,  Vector3 n2) {
	name = "Triangle";
	boundingVolume = false;

	this->p0 = p0;
	this->p1 = p1;
	this->p2 = p2;

	this->n0 = n0;
	this->n1 = n1;
	this->n2 = n2;

	n = Vector3::crossProduct(p1-p0, p2-p0);
	area = n.length()/2.0;
	n.normalize();
}

Triangle::Triangle(Vector3 p0, Vector3 p1, Vector3 p2) {
	name = "Triangle";
	boundingVolume = false;

	this->p0 = p0;
	this->p1 = p1;
	this->p2 = p2;

	n = Vector3::crossProduct(p1-p0, p2-p0);
	area = n.length()/2.0;
	n.normalize();
}

//Determines the intersection with the given ray
float Triangle::tIntersect(Vector3 p, Vector3 r, Object* obj) {
	r.normalize();
	Vector3 normal = n;

	float distanceToTrianglePlane = -Vector3::dotProduct((p - p0), normal) / Vector3::dotProduct(r, normal);
	Vector3 point = p + Vector3(r.x*distanceToTrianglePlane, r.y*distanceToTrianglePlane, r.z*distanceToTrianglePlane);

	if (Vector3::dotProduct(Vector3::crossProduct(p1-p0, point-p0), normal) < 0) return -1;
	if (Vector3::dotProduct(Vector3::crossProduct(p2-p1, point-p1), normal) < 0) return -1;
	if (Vector3::dotProduct(Vector3::crossProduct(p0-p2, point-p2), normal) < 0) return -1;

	obj = this;
	return distanceToTrianglePlane;
}

Object* Triangle::tIntersect(const Ray& ray, float& distance) {
	Vector3 dir = ray.direction;//r.normalize();
	dir.normalize();
	Vector3 origin = ray.origin;

	Vector3 normal = n;

	float distanceToTrianglePlane = -Vector3::dotProduct((origin - p0), normal) / Vector3::dotProduct(dir, normal);
	Vector3 point = origin + Vector3(dir.x*distanceToTrianglePlane, dir.y*distanceToTrianglePlane, dir.z*distanceToTrianglePlane);

	distance = -1;
	if (Vector3::dotProduct(Vector3::crossProduct(p1-p0, point-p0), normal) < 0) return this;
	if (Vector3::dotProduct(Vector3::crossProduct(p2-p1, point-p1), normal) < 0) return this;
	if (Vector3::dotProduct(Vector3::crossProduct(p0-p2, point-p2), normal) < 0) return this;

	distance = distanceToTrianglePlane;
	return this;
}

Vector3 Triangle::normal(Vector3 at) {
	//return n;
	Vector3 A = p1-p0;
	Vector3 B = p2-p0;
	Vector3 C = p2-p1;

	float lengthA = A.length();
	float lengthB = B.length();
	float lengthC = C.length();

	Vector3 zeroToMid = at - p0;
	Vector3 oneToMid = at - p1;

	float lengthZeroToMid = zeroToMid.length();
	float lengthOneToMid = oneToMid.length();

	//area of triangle0 (across from p0)
	//float areaT0 = g_abs(lengthC * lengthOneToMid * sin(acos(Vector3::dotProduct(C, oneToMid) / (lengthC*lengthOneToMid))));
	float areaT0 = Vector3::crossProduct(C, oneToMid).length()/2.0;

	//area of triangle1 (across from p1)
	//float areaT1 = g_abs(lengthB * lengthZeroToMid * sin(acos(Vector3::dotProduct(B, zeroToMid) / (lengthB*lengthZeroToMid))));
	float areaT1 = Vector3::crossProduct(B, zeroToMid).length()/2.0;

	//area of triangle2 (across from p2)
	//float areaT2 = g_abs(lengthA * lengthZeroToMid * sin(acos(Vector3::dotProduct(A, zeroToMid) / (lengthA*lengthZeroToMid))));
	float areaT2 = Vector3::crossProduct(A, zeroToMid).length()/2.0;

	Vector3 toReturn = n0*(areaT0/area);
	toReturn += n1*(areaT1/area);
	toReturn += n2*(areaT2/area);
	toReturn.normalize();
	
	return toReturn;
}

Vector3 Triangle::normal() {
	return n;
}

float Triangle::getArea() {
	return area;
}